package com.borderbears.backend.gui.viewers;

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;

import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.SwingWorker;

import com.borderbears.backend.media.MediaNode;

public class ImageViewer extends AbstractViewer {

	private final Logger log = Logger.getLogger(getClass().getName());

	private final ImageCanvas canvas;

	private final JLabel lbStatus;

	public ImageViewer() {

		setLayout(new BorderLayout());
		canvas = new ImageCanvas();
		add(canvas);

		lbStatus = new JLabel("Nothing to show.");
		add(lbStatus, BorderLayout.NORTH);
	}

	private void setStatus(final String msg) {
		final boolean show = (null != msg) && (msg.trim().length() > 0);
		if (show) {
			lbStatus.setText(msg);
		}
		lbStatus.setVisible(show);
	}

	@Override
	public void showNode(final MediaNode n) {
		final URL url = n.getURL();

		final SwingWorker<BufferedImage, Void> worker = new SwingWorker<BufferedImage, Void>() {
			@Override
			protected BufferedImage doInBackground() throws Exception {
				try {
					log.info("Loading " + url.toString());
					final BufferedImage im = ImageIO.read(url);
					if (null == im) {
						log.info("Loaded image was NULL");
					}
					return im;
				} catch (final IOException e) {
					setStatus("Could not load image.");
					log.warning("Error reading image from url: "
							+ n.getURL().toString());
				}
				return null;
			}

			@Override
			protected void done() {
				try {
					final BufferedImage im = get();
					if (null != im) {
						canvas.setImage(im);
						setStatus(null);
					}
				} catch (final InterruptedException e) {
					e.printStackTrace();
				} catch (final ExecutionException e) {
					e.printStackTrace();
				}
			}
		};
		worker.execute();

	}

}

class ImageCanvas extends Canvas {

	private BufferedImage image;

	public ImageCanvas() {
		addComponentListener(componentAdapter);
	}

	public void clear() {
		image.flush();
		image = null;
	}

	public void setImage(final BufferedImage im) {
		if (null != image) {
			image.flush();
		}
		image = im;
		repaint();
	}

	@Override
	public void update(final Graphics g1) {
		final Graphics2D g = (Graphics2D) g1;
		g.setColor(getBackground());
		g.fillRect(0, 0, getWidth(), getHeight());
		if (null != image) {
			float w = getWidth();
			float h = getHeight();
			final float r1 = (float) image.getWidth()
					/ (float) image.getHeight();
			final float r2 = w / h;
			if (r1 > r2) {
				// wider
				h = w / r1;
			} else {
				// taller
				w = h * r1;
			}

			final int imw = Math.round(w);
			final int imh = Math.round(h);

			final int x = (getWidth() - imw) / 2;
			final int y = (getHeight() - imh) / 2;

			g.drawImage(resize(image, imw, imh), x, y, null);

		}

	}

	private static BufferedImage resize(final BufferedImage image,
			final int width, final int height) {
		final int type = image.getType() == 0 ? BufferedImage.TYPE_INT_ARGB
				: image.getType();
		final BufferedImage resizedImage = new BufferedImage(width, height,
				type);
		final Graphics2D g = resizedImage.createGraphics();
		g.setComposite(AlphaComposite.Src);

		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
				RenderingHints.VALUE_INTERPOLATION_BILINEAR);

		g.setRenderingHint(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);

		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

		g.drawImage(image, 0, 0, width, height, null);
		g.dispose();
		return resizedImage;
	}

	private final ComponentAdapter componentAdapter = new ComponentAdapter() {
		@Override
		public void componentResized(final ComponentEvent e) {
			repaint();
		}
	};

}